package sample.exam

object SWord {
  def succ(s: String): String =
    if (s.eq(null) || s == "")
      ""
    else {
      val (result, _) =
        s.foldRight(Pair("", 0)) {
          case (BeLetter(c), (ss, be)) =>
            val ch = if (be == 1) letters(c) else c
            if (ch == 'z') (letters(c) + ss, 1)
            else (ch + ss, 0)

          case (BeUpper(c), (ss, be)) =>
            val ch = if (be == 1) uppers(c) else c
            if (ch == 'z') (uppers(c) + ss, 1)
            else (ch + ss, 0)


          case (BeDigit(c), (ss, be)) =>
            val ch = if (be == 1) digits(c) else c
            if (ch == 'z') (digits(c) + ss, 1)
            else (ch + ss, 0)
        }
      result
    }

  val letters: Map[Char, Char] = ('a' to 'z').map {
    case 'z' => 'z' -> 'a'
    case c => c -> (c + 1).toChar
  }.toMap

  val uppers: Map[Char, Char] = ('A' to 'Z').map {
    case 'Z' => 'Z' -> 'A'
    case c => c -> (c + 1).toChar
  }.toMap

  val digits: Map[Char, Char] = ('0' to '9').map {
    case '9' => '9' -> '0'
    case c => c -> (c + 1).toChar
  }.toMap

  object BeLetter {
    def unapply(c: Char): Option[Char] =
      if (Character.isLetter(c)) Some(c)
      else None
  }

  object BeUpper {
    def unapply(c: Char): Option[Char] =
      if (Character.isUpperCase(c)) Some(c)
      else None
  }

  object BeDigit {
    def unapply(c: Char): Option[Char] =
      if (Character.isDigit(c)) Some(c)
      else None
  }

  def main(args: Array[String]) {
    assert(succ("") == "")
    assert(succ("AA0z") == "AA1a")
    assert(succ("DBcZ9") == "DBdA0")
    assert(succ("Z9z") == "AA0z")
    assert(succ("bZz9") == "bAa0")
  }

}
